<template>
  <div id="app">
    <el-table
      :key="key"
      height="400"
      ref="dragTable"
      row-key="id"
      :data="treeTableData"
      :expand-row-keys="treeTableExpandKeys"
      border
      @expand-change="treeTableExpandChange"
    >
      <el-table-column prop="name" label="名字"></el-table-column>
      <el-table-column prop="age" label="年龄"></el-table-column>
      <el-table-column prop="desc" label="描述"></el-table-column>
    </el-table>
  </div>
</template>

<script>
import Sortable from 'sortablejs';
export default {
  name: 'App',
  components: {},
  data() {
    return {
      key: '',
      treeTableData: [
        {
          id: '1',
          name: '张三',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '2',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '3',
          name: '凌不疑',
          age: 18,
          desc: '三三',
          children: [
            {
              id: '4',
              name: '四四',
              age: 25,
              desc: '五五',
            },
            {
              id: '5',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
          ],
        },
        {
          id: '6',
          name: '凌不疑',
          age: 18,
          desc: '三三',
          children: [
            {
              id: '7',
              name: '四四',
              age: 25,
              desc: '五五',
            },
            {
              id: '8',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '9',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '10',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '11',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '12',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '13',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '14',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
            {
              id: '15',
              name: '不知道叫什么了',
              age: 26,
              desc: '哈哈哈',
            },
          ],
        },
        {
          id: '16',
          name: 'uu',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '17',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '18',
          name: 'shsh',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '19',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '20',
          name: 'bxfgs',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '21',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '22',
          name: 'gsthrth',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '23',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '24',
          name: 'srhhts',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '25',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '26',
          name: 'hdxhfchn',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '27',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
        {
          id: '28',
          name: 'bsr',
          age: 11,
          desc: '法外狂徒',
          children: [
            {
              id: '29',
              name: '月尊大人',
              age: 15,
              desc: '小兰花',
            },
          ],
        },
      ],
      flatTreeData: [],
      treeTableExpandKeys: [],
      sortableObj: null,
    };
  },
  mounted() {
    this.getAllIds(this.treeTableData);
    this.transverseNode(this.treeTableData, 1, (node, level, parentNode) => {
      node.level = level;
      node.parentId = parentNode ? parentNode.id : -1;
    });
    this.initSortable();
    this.getFlatNode(this.treeTableData, this.flatTreeData);
  },
  beforeDestroy() {
    if (this.sortableObj) {
      this.sortableObj.destroy();
    }
  },
  methods: {
    /**
     * 刷新table,防止滚动条跑到最上面
     */
    refreshTable() {
      const beforeScrollTop = this.$refs.dragTable.$el.querySelector(
        'div.el-table__body-wrapper'
      ).scrollTop;
      this.key = Math.random();
      setTimeout(() => {
        this.$refs.dragTable.$el.querySelector(
          'div.el-table__body-wrapper'
        ).scrollTop = beforeScrollTop;
      }, 0);
    },
    getAllIds(arr) {
      arr.map((item) => {
        this.treeTableExpandKeys.push(item.id);
        if (item.children && item.children.length > 0) {
          item.children.map((child) => this.treeTableExpandKeys.push(child.id));
        }
      });
    },
    initSortable() {
      // 获取容器元素
      const el = this.$refs.dragTable.$el.querySelectorAll(
        '.el-table__body-wrapper > table > tbody'
      )[0];

      if (!el) return;

      this.sortableObj = new Sortable(el, {
        group: 'dragName',
        draggable: '.el-table__row',
        onEnd: (evt) => {
          const { newIndex, oldIndex } = evt;
          const dragRow = this.flatTreeData[oldIndex];
          const relatedRow = this.flatTreeData[newIndex];
          if (dragRow.parentId !== relatedRow.parentId) {
            this.$message.warning('只能同层级内排序');
            this.reRender(null, 'treeTableData');
          } else {
            // 都无children
            if (!dragRow.children && !relatedRow.children) {
              const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
              this.flatTreeData.splice(newIndex, 0, oldData);
            }

            // drag有, relate无
            if (dragRow.children && !relatedRow.children) {
              const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
              this.flatTreeData.splice(newIndex, 0, oldData);

              if (newIndex < oldIndex) {
                // 有子元素的，子元素需要同样跟上来
                const flatChildren = [];

                this.getFlatNode(oldData.children || [], flatChildren);
                if (flatChildren.length > 0) {
                  for (let i = 1, len = flatChildren.length; i <= len; i++) {
                    const childData = this.flatTreeData.splice(
                      oldIndex + i,
                      1
                    )[0];
                    this.flatTreeData.splice(newIndex + i, 0, childData);
                  }
                }
              } else {
                // 有子元素的，子元素需要同样跟下来
                const flatChildren = [];

                this.getFlatNode(oldData.children || [], flatChildren);
                if (flatChildren.length > 0) {
                  for (let i = 1, len = flatChildren.length; i <= len; i++) {
                    const childData = this.flatTreeData.splice(oldIndex, 1)[0];
                    this.flatTreeData.splice(newIndex, 0, childData);
                  }
                }
              }
            }

            // drag无, relate有
            if (!dragRow.children && relatedRow.children) {
              const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
              this.flatTreeData.splice(newIndex, 0, oldData);

              if (newIndex > oldIndex) {
                // 有子元素的，子元素需要同样跟上来
                const flatChildren = [];

                this.getFlatNode(relatedRow.children || [], flatChildren);
                if (flatChildren.length > 0) {
                  for (let i = 1, len = flatChildren.length; i <= len; i++) {
                    const childData = this.flatTreeData.splice(
                      newIndex + i,
                      1
                    )[0];
                    this.flatTreeData.splice(newIndex + i - 1, 0, childData);
                  }
                }
              }
            }

            // drag有, relate有
            if (dragRow.children && relatedRow.children) {
              if (newIndex < oldIndex) {
                const oldData = this.flatTreeData.splice(oldIndex, 1)[0];
                this.flatTreeData.splice(newIndex, 0, oldData);

                // 有子元素的，子元素需要同样跟上来
                const flatChildren = [];

                this.getFlatNode(oldData.children || [], flatChildren);
                if (flatChildren.length > 0) {
                  for (let i = 1, len = flatChildren.length; i <= len; i++) {
                    const childData = this.flatTreeData.splice(
                      oldIndex + i,
                      1
                    )[0];
                    this.flatTreeData.splice(newIndex + i, 0, childData);
                  }
                }
              } else {
                const oldData = this.flatTreeData.splice(oldIndex, 1)[0];

                // relateRow的children数
                const relateFlatChildren = [];
                this.getFlatNode(relatedRow.children || [], relateFlatChildren);

                this.flatTreeData.splice(
                  newIndex + relateFlatChildren.length,
                  0,
                  oldData
                );

                // 有子元素的，子元素需要同样跟下来
                const flatChildren = [];

                this.getFlatNode(oldData.children || [], flatChildren);
                if (flatChildren.length > 0) {
                  for (let i = 1, len = flatChildren.length; i <= len; i++) {
                    const childData = this.flatTreeData.splice(oldIndex, 1)[0];
                    this.flatTreeData.splice(
                      newIndex + relateFlatChildren.length,
                      0,
                      childData
                    );
                  }
                }
              }
            }

            // 重新生成树的数据
            const data = this.getTreeData(this.flatTreeData, []);
            console.log('this.flatTreeData', this.flatTreeData, data);
            // 页面重新渲染
            this.reRender(data, 'treeTableData');
          }
        },
      });
    },
    getFlatNode(nodes, flatList, childrenKey = 'children') {
      nodes.forEach((node) => {
        flatList.push(node);
        if (node[childrenKey] && node[childrenKey].length) {
          this.getFlatNode(node[childrenKey], flatList);
        }
      });
    },
    getTreeData(nodes, resultList) {
      const childStack = [];
      let lastNode = {};
      nodes.forEach((node) => {
        delete node.children;

        const pushNode = (dataNode) => {
          const parentNode = childStack[childStack.length - 1];
          if (parentNode) {
            parentNode.children.push(dataNode);
          } else {
            resultList.push(dataNode);
          }
        };

        if (node.level < lastNode.level) {
          childStack.length = node.level - 1;
          pushNode(node);
        } else if (node.level === lastNode.level) {
          pushNode(node);
        } else if (node.level > lastNode.level) {
          if (!lastNode.children) {
            lastNode.children = [];
          }
          childStack.push(lastNode);
          pushNode(node);
        } else {
          resultList.push(node);
        }

        lastNode = node;
      });

      return resultList;
    },
    reRender(data, dataKey) {
      if (data) {
        this[dataKey] = [];
        this.$nextTick(() => {
          this[dataKey] = data;
        });
        console.log('data', data);
      } else {
        const origin = [].concat(this[dataKey]);
        this[dataKey] = [];
        this.$nextTick(() => {
          this[dataKey] = origin;
        });
      }
      // 防止滚动条重置
      this.refreshTable()
    },
    transverseNode(nodes, level = 1, cb, parentNode, childKey = 'children') {
      nodes.forEach((node) => {
        if (node[childKey] && node[childKey].length > 0) {
          this.transverseNode(node[childKey], level + 1, cb, node, childKey);
        }
        cb(node, level, parentNode);
      });
      return nodes;
    },
    treeTableExpandChange(row, expanded) {
      if (expanded) {
        this.treeTableExpandKeys.push(row.id);
      } else {
        const idx = this.treeTableExpandKeys.indexOf(row.id);
        this.treeTableExpandKeys.splice(idx, 1);
      }
      console.log('treeTableExpandKeys', this.treeTableExpandKeys);
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
